#include "TDAClienteCorreo.h"
#include "TDACorreo.h"
#include "vignere.h"
#include "logdebug.h"
#include "cola.h"

#include <string.h>
#include <stdlib.h>

/* TODAS LAS PRIMITIVAS Y FUNCIONES AUXILIARES PROBADAS Y FUNCIONANDO*/

/* Comienzo de funciones auxiliares */

/*
 * Encripta un correo
 * NOTA: se encripta solamente el cuerpo del correo
 *
 * Parametros:
 * correoLegible	un correo valido a ser encriptado
 * correoEncriptado	un puntero a una zona de memoria valida con espacio suficiente para contener un correo
 *
 * Valor de retorno:
 * N/A
 *
 * PRE: correoLegible es un correo valido
 * 		correoEncriptado apunta a una zona de memoria valida con especio suficiente para contener un correo
 * POST: se ha encriptado el correo provisto y la version encriptada puede obtenerse a partir del parametro correoEncriptado indicado
 *
 */
void encriptar(TDACorreo correoLegible, TDACorreo* correoEncriptado, char *clave) {
    int mov_ok=TRUE;
    Telem elem;
    TListaSimple lista;
    ls_Crear(&lista,sizeof(Telem));

    /*Copio el remitente*/
    setRemitente(correoEncriptado,correoLegible.De);
    /*Recorro la lista de destinatarios del correoLegible y la copio al correoEncriptado*/
    ls_Vaciar(&correoEncriptado->Para);
    getDestinatarios(correoLegible,&lista);
    if(ls_Vacia(lista)==FALSE) {
        ls_MoverCorriente(&lista,LS_PRIMERO);
        while (mov_ok==TRUE) {
            ls_ElemCorriente(lista,&elem);
            if(ls_Vacia(correoEncriptado->Para))
                ls_Insertar(&correoEncriptado->Para,LS_PRIMERO,&elem);
            else
                ls_Insertar(&correoEncriptado->Para,LS_SIGUIENTE,&elem);
            mov_ok=ls_MoverCorriente(&lista,LS_SIGUIENTE);
        }
    }
    /*Copio el asunto*/
    setAsunto(correoEncriptado,correoLegible.Asunto);
    /*Copio la fecha*/
    setFechaHoraEnviado(correoEncriptado,correoLegible.Fecha);
    /*Copio el nombre del archivo*/
    strcpy(correoEncriptado->nombre_del_archivo,correoLegible.nombre_del_archivo);
    /*Encripto el Cuerpo*/
    encriptarVignere(correoLegible.Cuerpo, clave, correoEncriptado->Cuerpo);
}

/*
 * Desencripta un correo
 *
 * Parametros:
 * correoEncriptado	un correo valido a ser desencriptado
 * correoLegible	un puntero a una zona de memoria valida con espacio suficiente para contener un correo
 *
 * Valor de retorno:
 * N/A
 *
 * PRE: correoEncriptado es un correo valido
 * 		correoLegible apunta a una zona de memoria valida con especio suficiente para contener un correo
 * POST: se ha desencriptado el correo provisto y la version desencriptada puede obtenerse a partir del parametro correoLegible indicado
 *
 */
void desencriptar(TDACorreo correoEncriptado, TDACorreo* correoLegible, char *clave) {
    int mov_ok=TRUE;
    Telem elem;
    TListaSimple lista;
    ls_Crear(&lista,sizeof(Telem));

    /*Copio el remitente*/
    setRemitente(correoLegible,correoEncriptado.De);
    /*Recorro la lista de destinatarios del correoEncriptado y la copio al correoLegible*/
    getDestinatarios(correoEncriptado,&lista);
    ls_Vaciar(&correoLegible->Para);
    if(ls_Vacia(lista)==FALSE) {
        ls_MoverCorriente(&lista,LS_PRIMERO);
        while (mov_ok==TRUE) {
            ls_ElemCorriente(lista,&elem);
            if(ls_Vacia(correoLegible->Para))
                ls_Insertar(&correoLegible->Para,LS_PRIMERO,&elem);
            else
                ls_Insertar(&correoLegible->Para,LS_SIGUIENTE,&elem);
            mov_ok=ls_MoverCorriente(&lista,LS_SIGUIENTE);
        }
    }
    /*Copio el asunto*/
    setAsunto(correoLegible,correoEncriptado.Asunto);
    /*Copio la fecha*/
    setFechaHoraEnviado(correoLegible,correoEncriptado.Fecha);
    /*Copio el nombre del archivo*/
    strcpy(correoLegible->nombre_del_archivo,correoEncriptado.nombre_del_archivo);
    /*Desencripto el cuerpo*/
    desencriptarVignere(correoEncriptado.Cuerpo, clave, correoLegible->Cuerpo);
}

/* Fin de funciones auxiliares */

void crearClienteCorreo(TDAClienteCorreo* clienteCorreo, char* direcUsr) {

    /*Creo un cliente de correo con la dirección del usuario e inicializo valores*/
    clienteCorreo->direcServer = NULL;
    strcpy(clienteCorreo->direcUsr, direcUsr);
    strcpy(clienteCorreo->clave, "\0");
}

void destruirClienteCorreo(TDAClienteCorreo* clienteCorreo) {

   /*Elimino el cliente de correo y su contenido y borro valores*/
    clienteCorreo->direcServer = NULL;
    strcpy(clienteCorreo->direcUsr, "\0");
    strcpy(clienteCorreo->clave, "\0");
}

void getDirecUsr(TDAClienteCorreo clienteCorreo, char* direcUsr) {
	strcpy(direcUsr, clienteCorreo.direcUsr);
}

void enviarClave(TDAClienteCorreo clienteCorreo, TDACanalSeguro* canalSeguro) {
    setContenido(canalSeguro, clienteCorreo.clave);
}

void obtenerClave(TDAClienteCorreo* clienteCorreo, TDACanalSeguro canalSeguro) {
    getContenido(canalSeguro, clienteCorreo->clave);
}

int conectar(TDAClienteCorreo* clienteCorreo, TDAServidorInseguro* servidorInseguro) {

    /*Conecto y guardo la "dirección" del servidor inseguro en el Cliente de correo*/
    clienteCorreo->direcServer = servidorInseguro;
	return 1;
}

int estaConectado(TDAClienteCorreo clienteCorreo) {
    if(clienteCorreo.direcServer==NULL)
        return FALSE;
    else
        return TRUE;
}

void desconectar(TDAClienteCorreo* clienteCorreo) {

    /*Desconecto el servidor y borro la "dirección" del servidor inseguro*/
    clienteCorreo->direcServer = NULL;
}

int enviarCorreo(TDAClienteCorreo clienteCorreo, TDACorreo correo) {

    /*Creo un correo para contener correo encriptado se va a enviar*/
    TDACorreo CorreoEncriptado;
    crearCorreo(&CorreoEncriptado);

    /*Encripto el correo y lo agrego al servidor*/
    encriptar(correo,&CorreoEncriptado,clienteCorreo.clave);
    if((agregarCorreo(clienteCorreo.direcServer, CorreoEncriptado) != 0)) return 1;
	else return 0;
}

int recibirProximoCorreo(TDAClienteCorreo clienteCorreo, TDACorreo* correo) {

	/*Creo un correo para contener el correo encriptado que se va a recibir*/
    TDACorreo CorreoEncriptado;

    /*Obtengo proximo correo desde el servidor para este cliente de correo*/
    crearCorreo(&CorreoEncriptado);
	if (obtenerProximoCorreo(clienteCorreo.direcServer, clienteCorreo.direcUsr, &CorreoEncriptado)==TRUE) {
        /*Desencripto el correo recibido*/
        desencriptar(CorreoEncriptado,correo,clienteCorreo.clave);
        return TRUE;
	} else return FALSE; /* Si no hay correos para este destinatario*/
}

int obtenerTodos(TDAClienteCorreo cliente, TListaSimple *correos) {
    TDACorreo elem;
    crearCorreo(&elem);
    TCola Cola_correos;
    C_Crear(&Cola_correos,sizeof(elem));
    obtenerCorreos(cliente.direcServer, cliente.direcUsr, &Cola_correos);
    ls_Vaciar(correos);
    while(C_Vacia(Cola_correos)==FALSE) {
        C_Sacar(&Cola_correos,&elem);
        desencriptar(elem,&elem,cliente.clave);
        if (ls_Vacia(*correos)==TRUE)
            ls_Insertar(correos,LS_PRIMERO,&elem);
        else
            ls_Insertar(correos,LS_SIGUIENTE,&elem);
        crearCorreo(&elem);
    } /*Deberia insertarlo ordenado NO FUNCIONA LA FUNCION AUXILIAR*/
    return FALSE;
}
